package com.cskaoyan.javase.oop1._7constructor;

/**
 * 构造器
 * 案例:
 * 创建一个教师类，有课程和年龄两个属性，行为是可以上课。
 * 现在我们需要创建以下对象：
 * 1. 18岁的Java老师对象
 * 2. 28岁的C++老师对象
 * 3. 30岁的Python老师对象
 * 4. ...
 *
 * 按照之前我们的做法，需要先创建出对象，再进行成员变量的赋值，这样做如果只有一个两个对象还好，如果需要创建很多对象，就有点过于麻烦了，对象的属性，能不能"出厂"的时候就设定好呢？
 * 是可以的,这就需要，为了灵活的创建对象,给成员变量赋值,我们需要使用构造器来完成这个功能。
 *
 * 构造器,也叫构造方法(constructor),它是一种特殊的方法,作用是在创建对象过程中给成员变量赋值。它的特殊点在以下:
 *      1.语法很特殊,构造器的语法如下:
 *          [访问权限修饰符] 类名(形参列表){
 *              // 方法体
 *          }
 *          访问权限修饰符这里,我们默认是public
 *          构造器没有返回值,也不需要返回值类型
 *          构造方法的名字和类名保持完全一致,某个类的构造方法的名字必须和类名一模一样
 *              所以,类名是大驼峰的,构造器的名字也是大驼峰的
 *          形参列表和方法体和正常的方法是一样的
 *
 *      2.它不是普通方法,它的调用方式也和普通方法不同. 构造器不能让程序员直接调用,而是在创建对象过程中
 *          由JVM自动去调用
 *          但是虽然程序员不能直接调用,但是可以指示JVM在创建对象时,究竟使用哪个构造方法
 *          语法:
 *              new 构造器名/类名(实参);
 *          解释: 只要使用new关键字创建对象,就一定会调用构造方法,通过实参来确定调用该类的哪个构造方法
 *          这就意味着一个类的构造方法,完全可能不止一个,多个构造器之间构成方法重载,它们的形参列表一定不同
 *
 *      3.我们之前创建的所有对象,都是用new调用一个类的无参构造,来创建的对象.
 *          这说明任何一个Java类,只要没有直接提供任何一个构造方法,那么就隐式提供默认构造器(无参构造器)
 *          默认无参构造器的格式:
 *          public 类名(){}
 *      4.构造器的作用是用来给对象的成员变量赋值用的，无参构造器显然做不到这一点，所以我们需要有参构造器。
 *          有参构造器的语法：
 *          [访问权限修饰符] 类名(形参列表){
 *              this.成员变量名 = 形参名;
 *              ...
 *          }
 *          注：构造器中也隐含this传参，指向当前对象
 *
 *
 * 构造器使用的细节/注意事项：
 *      1.默认无参构造器只在一个类没有任何构造器时，才会提供。一旦这个类有任何一个构造器，默认无参就不会提供了。
 *      2.构造器之间是方法重载，要注意一定要形参列表不同。形参名不同，并不能构成方法重载。
 *      3.构造器是有标准格式的，类似于：
 *          public 类名(形参列表){
 *              this.成员变量名 = 形参名;
 *              ...
 *          }
 *          或者
 *          public 类名(){}
 *          称之为"标准格式构造器"
 *
 *          使用标准格式构造器创建对象，成员变量的取值一定是准确的（你给的实参是什么，赋的值就是什么）。
 *
 *       4.构造器的赋值一定在一个对象所有赋值方式最后一步进行，这是为了构造器赋值的准确性。
 *       5.标准构造器格式很固定，我们不需要自己写，idea可以自动生成。用快捷键alt + insert
 *          建议大家以后构造器，直接用快捷键写就可以了。
 *          建议大家在写一个实体类（需要创建对象，存储成员变量的类）时，先顺手给出默认无参。这是一个很好的习惯。
 *       6.构造器中的this也能够访问对象的成员方法这些东西，但是意义不大。也不要在构造器中乱写代码。构造器的代码应该尽量少，如果对象的初始化赋值需要很多代码完成，那就抽取出方法，而不是把所有代码都写在构造器中。
 *
 *       7.在构造器中，可以使用this(实际参数)去调用别的构造器，根据实参的类型和有无决定调用哪个构造器。
 *       this在表示调用构造器时，必须在这个构造器的第一行代码。当然表示调用构造器时，只能用一次。
 *
 *      8.每new创建一个对象，都会调用一次构造方法，而类加载仅有一次。
 *
 *
 *
 *
 *
 * @since 17:34
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // 创建教师对象
        Teacher t = new Teacher();
        t.course = "JavaSE";
        t.age = 18;
        t.name = "长风";

        Teacher t2 = new Teacher();
        t2.course = "C++";
        t2.age = 30;
        t2.name = "龙哥";

        // 使用三参构造器创建对象
        Teacher t3 = new Teacher("王冰冰", "新闻广播", 18);
        t3.print();


    }
}

// 定义教师类
class Teacher {
    String name;
    String course;
    int age;
    double salary;

    public void teach() {
        System.out.println(age + "岁的" + name + "老师,在讲" + course);
    }

    // 默认无参构造器
    public Teacher() {
        // init();
    }

    /*public void init(){
        // 二十行代码完成对象初始化
    }*/

    // 单参构造器
    public Teacher(String name) {
        this.name = name;
    }

    // 单参构造器
    // public Teacher(String course){
    //     this.course = course;
    // }

    // 三参构造器
    public Teacher(String name, String course, int age) {
        // 用形参给成员变量赋值
        this.name = name;
        this.course = course;
        this.age = age;
    }

    public Teacher(String name, String course) {
        this.name = name;
        this.course = course;
    }

    public Teacher(String name, String course, int age, double salary) {
        // 使用this关键字去调用其它构造器
        this(name, course, age);
        this.salary = salary;
    }


    // 打印成员变量的方法
    public void print() {
        System.out.println("名字是：" + name + "的" + age + "岁老师，他在教授:" + course);
    }


}